/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package dmcn.bl.genetics.execute;

import dmcn.bl.genetics.fitnessfunction.AssignTerminalFitnessFunction;
import dmcn.bl.genetics.fitnessfunction.Evaluator;
import dmcn.bl.genetics.gui.GuiController;
import java.lang.Integer;
import java.math.BigInteger;
import java.util.Arrays;
import org.jgap.*;
import org.jgap.impl.CrossoverOperator;
import org.jgap.impl.DefaultConfiguration;
import org.jgap.impl.IntegerGene;
import org.jgap.impl.MutationOperator;

/**
 *
 * @author Home
 */
public class ExecuteGenetic {

    private int numOfConcetrators;
    private int numOfTerminals;
    private int[][] cost;
    private int[] fortio;
    private int[] xwritikothta;

    public void executeGenetic(//Input input,
            int numOfConcetrators,
            int numOfTerminals,
            int[][] exeCost,
            int[] exeFortio,
            int[] exeXwritikothta,
            int populationSize,
            int numOfEvolves,
            boolean moreOptions,
            int mutation,
            double crossOver,
            double approximationOffset,
            int maxApproximationCount) throws InvalidConfigurationException {

        this.numOfConcetrators = numOfConcetrators;
        this.numOfTerminals = numOfTerminals;
        this.cost = exeCost;
        this.fortio = exeFortio;
        this.xwritikothta = exeXwritikothta;
        long startTime = System.currentTimeMillis();
        Configuration conf = new DefaultConfiguration() {

            FitnessEvaluator evaluator = new DefaultFitnessEvaluator() {

                @Override
                public boolean isFitter(double a_fitness_value1, double a_fitness_value2) {
                    return a_fitness_value2 > a_fitness_value1;
                }
            };

            @Override
            public FitnessEvaluator getFitnessEvaluator() {
                return evaluator;
            }
        };
        if (moreOptions) {
            conf.addGeneticOperator(new CrossoverOperator(conf));//, crossOver));
            conf.addGeneticOperator(new MutationOperator(conf));//, mutation));
        }
        conf.setPreservFittestIndividual(true);
        conf.setKeepPopulationSizeConstant(true);
        AssignTerminalFitnessFunction ff = new AssignTerminalFitnessFunction(numOfConcetrators, numOfTerminals, exeCost, exeFortio, exeXwritikothta);
        conf.setFitnessFunction(ff);
        //edw bazeis 0,1
        Gene[] sampleGenes = new Gene[numOfConcetrators * numOfTerminals];
        for (int i = 0; i < numOfConcetrators * numOfTerminals; i++) {
            sampleGenes[i] = new IntegerGene(conf, 0, 1);
        }
        IChromosome sampleChromosome = new Chromosome(conf, sampleGenes);
        conf.setSampleChromosome(sampleChromosome);
        conf.setPopulationSize(populationSize);
        Genotype genotype;
//        genotype = Genotype.randomInitialGenotype(conf);
        Population population = new Population(conf, getGreedySolution(conf, populationSize));
        genotype = new Genotype(conf, population);
        IChromosome bestSolutionSoFar;

        GuiController guiController = new GuiController(numOfConcetrators, numOfTerminals, exeCost, exeFortio, exeXwritikothta);

//        for (int i = 0; i < numOfEvolves; i++) {
//            population.evolve();
//
//        }
        boolean evolve = true;
        double previousFitness;
        double currentFitness;
        int approximationCount = 0;
        genotype.evolve();
        while (evolve) {
            previousFitness = genotype.getFittestChromosome().getFitnessValue();
            genotype.evolve();
            currentFitness = genotype.getFittestChromosome().getFitnessValue();
            if (previousFitness - currentFitness < approximationOffset && currentFitness != Integer.MAX_VALUE) {
                approximationCount++;
            } else {
                approximationCount = 0;
            }
            if (approximationCount > maxApproximationCount) {
                evolve = false;
            }
            guiController.setBestSolutionSoFar(genotype.getFittestChromosome());
            guiController.paint();
        }
        bestSolutionSoFar = genotype.getFittestChromosome();

        /*
         * print solution to log
         */

        System.out.println("The best solution has a fitness value of "
                + bestSolutionSoFar.getFitnessValue());

        System.out.println("The best solution is: ");
        System.out.print("   ");
        for (int i = 0; i < numOfTerminals; i++) {
            System.out.print((i + 1) + " ");
        }
        System.out.println("");
        int j = 0;
        for (int i = 0; i < bestSolutionSoFar.getGenes().length; i++) {
            if ((i) % numOfTerminals == 0) {
                System.out.print(++j + ": ");
            }
            System.out.print(bestSolutionSoFar.getGenes()[i].getAllele() + " ");
            if ((i + 1) % numOfTerminals == 0) {
                System.out.println("");

            }

        }
        long endTime = System.currentTimeMillis();
        System.out.println("execute at : " + (endTime - startTime) / 1000 + " seconds");
        Configuration.reset();

    }

    private IChromosome[] getGreedySolution(Configuration conf, int popsize) throws InvalidConfigurationException {
        IChromosome[] chromosomes = new IChromosome[popsize];
        int z = 0;
        Evaluator evaluator = new Evaluator(numOfConcetrators, numOfTerminals, cost, fortio, xwritikothta);
        int[] bits = new int[numOfConcetrators * numOfTerminals];
        for (int i = 0; i < bits.length; i++) {
            bits[i] = 1;
        }
        String binary = Arrays.toString(bits).replace("[", "").replace("]", "").replace(", ", "");
//        Integer max = Integer.parseInt(binary, 2);
        BigInteger max = new BigInteger(binary, 2);
        System.out.println("possible solutions: " + max);
        BigInteger i = BigInteger.valueOf(0);
        while (i.compareTo(max) == -1 && z < popsize) {//gia ka8e pi8anh lush-xromosoma
            Chromosome chromosome = new Chromosome(conf);
//            String s = Integer.toBinaryString(i);
            String s = i.toString(2);
            while (s.length() < bits.length) {
                s = "0" + s;
            }
            char[] genesCharArray = s.toCharArray();
            Gene[] genes = new Gene[bits.length];//genes
            for (int j = 0; j < genesCharArray.length; j++) {//gia ka8e pi8ano gene
                char c = genesCharArray[j];
                Gene gene = new IntegerGene(conf, 0, 1);
                gene.setAllele(Integer.parseInt(new String(new char[]{c})));
                genes[j] = gene;
            }
            chromosome.setGenes(genes);
            if (evaluator.evaluate(chromosome) != null) {
                chromosomes[z] = chromosome;
                z++;
                System.out.println("greedy solution: " + z);
            }
//            System.out.println("greedy step: " + i);
            i = i.add(BigInteger.valueOf(1));
        }

        return chromosomes;
    }
}
